package br.senai.sc.controller.business;

import java.io.Serializable;
import java.math.BigInteger;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.international.status.builder.BundleKey;

import br.senai.sc.model.BaciaHidrografica;
import br.senai.sc.model.Cidade;
import br.senai.sc.model.CorpoHidrico;
import br.senai.sc.model.Estado;
import br.senai.sc.util.SystemConstants;

/**
 * @author Fernando Marquardt &lt;fernando.marquardt@sc.senai.br&gt;
 * @since 26/01/2012
 * @version $Id: CidadeBusiness.java 28 2012-03-07 20:48:20Z fernando.marquardt
 *          $
 */
public class CidadeBusiness implements Serializable {

	private static final long serialVersionUID = 1L;

	@PersistenceContext
	private EntityManager em;

	@Inject
	private Messages messages;

	/**
	 * Verifica se existe uma {@link Cidade} com o mesmo
	 * {@link Cidade#getNome()} cadastrado.
	 * 
	 * @param cidade
	 */
	public boolean cidadeComMesmoNome(Cidade cidade) {

		if ((cidade == null) || (cidade.getNome() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM cidade c WHERE nome LIKE :nome")
				.setParameter("nome", cidade.getNome()).getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param estado
	 * @return True caso o {@link Estado} exista, false caso contrário
	 */
	public boolean estadoExiste(Estado estado) {

		if ((estado == null) || (estado.getIdEstado() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM estado e WHERE id_estado = :idEstado")
				.setParameter("idEstado", estado.getIdEstado())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param cidade
	 * @return True caso a {@link Cidade} exista, false caso contrário.
	 */
	public boolean cidadeExiste(Cidade cidade) {

		if ((cidade == null) || (cidade.getIdCidade() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM cidade c WHERE id_cidade = :idCidade")
				.setParameter("idCidade", cidade.getIdCidade())
				.getSingleResult();
		return total.intValue() > 0;
	}

	/**
	 * @param cidade
	 * @return True caso exista uma {@link Cidade} com mesmo nome, porém com id
	 *         diferente, false caso contrário.
	 */
	public boolean cidadeComMesmoNomeIdDiferente(Cidade cidade) {

		if ((cidade == null) || (cidade.getNome() == null)
				|| (cidade.getIdCidade() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM cidade c WHERE nome LIKE :nome AND id_cidade != :idCidade")
				.setParameter("nome", cidade.getNome())
				.setParameter("idCidade", cidade.getIdCidade())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param cidade
	 * @return True caso a {@link Cidade} possui referência para
	 *         {@link BaciaHidrografica}, false caso contrário.
	 */
	public boolean contemBaciaHidrografica(Cidade cidade) {

		if ((cidade == null) || (cidade.getIdCidade() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM bacia_hidrografica_cidade bhc WHERE id_cidade = :idCidade")
				.setParameter("idCidade", cidade.getIdCidade())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param cidade
	 * @return True caso a {@link Cidade} possui referência para
	 *         {@link CorpoHidrico}, false caso contrário.
	 */
	public boolean contemCorpoHidrico(Cidade cidade) {

		if ((cidade == null) || (cidade.getIdCidade() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM corpo_hidrico_cidade ch WHERE id_cidade = :idCidade")
				.setParameter("idCidade", cidade.getIdCidade())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @return True caso existe {@link Cidade} cadastrada no sistema, false caso
	 *         contrário.
	 */
	public boolean existeCidadeCadastrada() {

		BigInteger total = (BigInteger) em.createNativeQuery(
				"SELECT count(*) FROM cidade c").getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Cidade} pode
	 * ser salva. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param cidade
	 * @return True caso a {@link Cidade} pode ser salva, false caso contrário.
	 */
	public boolean podeSalvarCidade(Cidade cidade) {

		messages.clear();
		if (cidadeComMesmoNome(cidade)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.cidadeComMesmoNome"));
		}

		if (!estadoExiste(cidade.getEstado())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.estadoInexistente"));
		}

		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Cidade} pode
	 * ser editada. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param cidade
	 * @return True caso a {@link Cidade} pode ser editada, false caso
	 *         contrário.
	 */
	public boolean podeEditarCidade(Cidade cidade) {

		messages.clear();
		if (!cidadeExiste(cidade)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.cidadeInexistente"));
		}

		if (!estadoExiste(cidade.getEstado())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.estadoInexistente"));
		}

		if (cidadeComMesmoNomeIdDiferente(cidade)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.cidadeComMesmoNome"));
		}

		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Cidade} pode
	 * ser removida. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param cidade
	 * @return True caso a {@link Cidade} pode ser removida, false caso
	 *         contrário.
	 */
	public boolean podeRemoverCidade(Cidade cidade) {

		messages.clear();
		if (!cidadeExiste(cidade)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.cidadeInexistente"));
		}

		if (contemBaciaHidrografica(cidade)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"cidades.validacao.baciaHidrograficaPossuiCidade"));
		}

		return messages.isEmpty();
	}

}